﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IndieStudio.BugsBang.Utility;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine.SceneManagement;

///Developed By Indie Studio
///https://assetstore.unity.com/publishers/9268
///www.indiestd.com
///info@indiestd.com

namespace IndieStudio.BugsBang.Game
{
	[DisallowMultipleComponent]
	public class Levels : MonoBehaviour
	{
		/// <summary>
		/// The level locked,unlocked sprites
		/// </summary>
		public Sprite levelLocked, levelUnLocked;

		/// <summary>
		/// Star on/off sprites.
		/// </summary>
		public Sprite starOn, starOff;

		/// <summary>
		/// The stars score counter.
		/// </summary>
		public ScoreCounter starsScore;

		/// <summary>
		/// The levels array.
		/// </summary>
		public GameObject[] levels;

		/// <summary>
		/// The content of the levels.
		/// </summary>
		public Transform levelsContent;

		/// <summary>
		/// Whether lerp to last reached level or not.
		/// </summary>
		public static bool lerpToLastReached = true;

		/// <summary>
		/// Wehther all levels completed or not.
		/// </summary>
		public static bool levelsCompleted;

		/// <summary>
		/// A static instance of this class.
		/// </summary>
		public static Levels instance;

		void Awake ()
		{
			if (instance == null)
				instance = this;
		}

		// Use this for initialization
		void Start ()
		{
			//Set up references

			levels = CommonUtil.FindGameObjectsOfTag ("Level");

			if (Levels.instance.levels.Length != LevelsManager.instance.levels.Count) {
				Debug.LogError ("Number of levels in the <b>Levels Manager</b> gameobject does not equal number of levels in the <b>Levels scene</b>");
				//return;
			}

			if (starsScore != null) {
				//Set up stars score value
				starsScore.fromValue = 0;
				starsScore.toValue = LevelsManager.instance.GetCollectedStars();
				starsScore.Run ();
			}

			if (lerpToLastReached) {
				//Show levels with animation
				StartCoroutine ("ScaleUpLevels");
			} else {
				//Show levels without animation
				foreach (GameObject lvl in levels) {
					lvl.GetComponent<Animator> ().SetTrigger ("InstantScale");
				}
			}
		
			if (levelsCompleted) {
				DataManager.SaveLevelsCompletedValue (1);
				levelsCompleted = false;
				UIEvents.instance.ShowLevelsCompletedDialog ();
			}
		}

		/// <summary>
		/// Scale up levels coroutine.
		/// </summary>
		private IEnumerator ScaleUpLevels ()
		{
			yield return 0;

			foreach (GameObject lvl in levels) {
				lvl.GetComponent<Animator> ().SetTrigger ("ScaleUp");
				yield return new WaitForSeconds (0.05f);
			}
		}

		void FixedUpdate ()
		{
			//Optimize (Tris,Verts) by realsing level resources (image,text,button) of far levels
			foreach (GameObject lvl in levels) {
				if (Vector2.Distance (transform.position, lvl.transform.position) > 8) {
					lvl.GetComponent<Level> ().HideResources ();
				} else {
					lvl.GetComponent<Level> ().ShowResources ();
				}
			}
		}

		/// <summary>
		/// Move the container close to the level.
		/// </summary>
		/// <param name="level">Level.</param>
		public void MoveNearByLevel (Level level)
		{
			if (levelsContent == null) {
				Debug.LogWarning ("LevelsContent reference is undefined in Levels component");
				return;
			}

			//Skip this fucntion , for first 10 levels
			if (level.ID <= 10) {
				lerpToLastReached = false;
				return;
			}

			Vector3 tempPos = levelsContent.position;
			Vector3 screenHeight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width,Screen.height)) - Camera.main.ScreenToWorldPoint(Vector3.zero) ;

			//Calculate the y-offset, for the last 5 levels the offset will be less than the other levels
			//You can change this offset , for last n level as you want
			float yOffset;
			if (level.ID >= levels.Length - 5) {
				yOffset = screenHeight.y * 0.35f;
			}else if (level.ID > 10) {
				yOffset = screenHeight.y* 0.85f;
			}else {
				yOffset = screenHeight.y;
			}

			tempPos.y = levelsContent.position.y + (levelsContent.position.y-level.transform.position.y) - yOffset;

			if (lerpToLastReached) {
				//Lerp to the last reached level
				TransformFollow2D tf2D = levelsContent.GetComponent<TransformFollow2D> ();
				tf2D.target.transform.position = tempPos;
				tf2D.onReachTargeEvent.AddListener (() => level.CreateHighLight ());
				tf2D.Move ();
			} else {
				//Move instantly to the last reached level
				levelsContent.transform.position = tempPos;
			}
		}

		/// <summary>
		/// On destroy this instance event.
		/// </summary>
		void OnDestroy ()
		{
			StopAllCoroutines ();
		}

		#if UNITY_EDITOR

		/* 
		 * This block of code works in the unity editor only
		*/

		[MenuItem ("Tools/Bugs Bang Pack/Levels Scene/New Level #l", false, 0)]
		static void CreateNewPathMenu ()
		{
			int levelsCount = GameObject.FindObjectsOfType<Level> ().Length;
			int levelID = levelsCount + 1;

			GameObject lastLevel = GameObject.Find ("Level-" + CommonUtil.IntToString (levelsCount));
			Transform levelParent = GameObject.Find("Levels").transform.Find("Viewport").Find("Content");
			GameObject levelPrefab = Resources.Load<GameObject> ("Level");

			if (levelPrefab == null) {
				Debug.LogWarning ("Level prefab is not defined in the Resources folder");
				return;
			}

			GameObject newLevel = Instantiate (levelPrefab, lastLevel == null ? Vector3.zero : lastLevel.transform.position, Quaternion.identity) as GameObject;
			newLevel.GetComponent<Level> ().ID = levelID;
			newLevel.name = "Level-" + CommonUtil.IntToString (levelID);
			newLevel.transform.SetParent (levelParent);
			newLevel.transform.localScale = Vector3.one;
			newLevel.GetComponent<RectTransform> ().SetAsLastSibling ();

			Selection.activeGameObject = newLevel ;
			DirtyUtil.MarkSceneDirty ();

			Debug.Log ("New "+newLevel.name+" is created");
		}

		[MenuItem ("Tools/Bugs Bang Pack/Levels Scene/New Level #l", true, 0)]
		static bool CreateNewPathMenuValidate ()
		{
			return SceneManager.GetActiveScene ().name == "Levels" ;
		}
		#endif
	}
}